/*
 * ------------------------------------------------------------------
 * Copyright © 2017, Hangzhou DtDream Technology Co.,Ltd. All rights reserved.
 * ------------------------------------------------------------------
 * Product : DTPortal
 * Module Name : test
 * Date Created: 2017/7/26 下午4:41
 * Description :
 *  ---------------------------------------------------------------------------------------------------------------
 *  Modification History * DATE Name Description
 *  ----------------------------------------------------------------------------------------------------------------
 */

package io.renren.common.utils.zwtConn;

import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @author dukexx
 * @date 2017/7/26
 * @since 1.0.0
 */
@Slf4j
public class ECDSAUtil {

    public static final String ALGORITHM = "SHA256withECDSA";

    /**
     * 采用 ECDSA 加签
     *
     * @param data   加签的数据
     * @param priKey 私钥
     * @return
     * @throws Exception
     */
    public static String signStr(String data, String priKey) {
        return sign(data.getBytes(StandardCharsets.UTF_8), priKey);
    }

    public static String sign(byte[] data, String priKey) {
        try {
            PrivateKey privateKey = getPrivateKey(priKey);
            Signature signature = Signature.getInstance(ALGORITHM);
            signature.initSign(privateKey);
            signature.update(data);
            return encryptBASE64(signature.sign());
        } catch (Exception e) {
            log.error("can not sign data by ECDSA256, because ", e);
            return "";
        }
    }


    /**
     * 采用 ECDSA 验签
     *
     * @param data   加签数据
     * @param pubKey 公钥
     * @param sign   签名
     * @return
     * @throws Exception
     */
    public static boolean verifyStr(String data, String pubKey, String sign){
        return verify(data.getBytes(StandardCharsets.UTF_8), pubKey, sign);
    }

    public static boolean verify(byte[] data, String pubKey, String sign){
        Signature signature;
        try {
            signature = Signature.getInstance(ALGORITHM);
            PublicKey publicKey = getPublicKey(pubKey);
            signature.initVerify(publicKey);
            signature.update(data);
            return signature.verify(decryptBASE64(sign));
        } catch (Exception e) {
            log.error("can not verify data by ECDSA256, because ",e);
            return false;
        }
    }


    private static PrivateKey getPrivateKey(String priKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decryptBASE64(priKey));
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    }

    private static PublicKey getPublicKey(String pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decryptBASE64(pubKey));
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePublic(x509EncodedKeySpec);
    }

    /** base64解密 */
    private static byte[] decryptBASE64(String key) {
        return Base64.getDecoder().decode(key);
    }

    /** base64加密 */
    private static String encryptBASE64(byte[] bytes) {
        return new String(Base64.getEncoder().encode(bytes), StandardCharsets.UTF_8);
    }


    public static final String PRIVATE_KEY = "privateKey";

    public static final String PUBLIC_KEY = "publicKey";

    /**
     * 生成 ECDSA 密钥对
     *
     * @return
     */
    public static Map<String, String> buildKeyPairBase64() {
        KeyPairGenerator keyPairGenerator;
        try {
            //采用ECDSA初始化密钥
            keyPairGenerator = KeyPairGenerator.getInstance("EC");
            keyPairGenerator.initialize(256);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            //生成私钥
            ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate();
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            //生成公钥
            ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic();
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(ecPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance("EC");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

            Map<String, String> keyPairMap = new HashMap<>(2);
            keyPairMap.put(PRIVATE_KEY, encryptBASE64(privateKey.getEncoded()));
            keyPairMap.put(PUBLIC_KEY, encryptBASE64(publicKey.getEncoded()));
            return keyPairMap;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
      Map<String, String> map = buildKeyPairBase64();
        System.out.println("privateKey: " + map.get("privateKey"));
        System.out.println("publicKey: " + map.get("publicKey"));
        String publicKey = map.get("publicKey");
        // 自身的私钥
        String privateKey =map.get("privateKey");

        //消息原文
        String body = "HelloWord123";
        // 生成签名信息
        String sign = ECDSAUtil.signStr(body, privateKey);
        System.out.println("sign:"+sign);
        System.out.println("消息原文:"+body);

        // 进行验签
        boolean isyQ = ECDSAUtil.verifyStr(body, publicKey, sign);
        System.out.println(isyQ);
    }

}
